#include "adc.h"
#include "main.h"
#include "adc_config.h"
#include "utility.h"
#include <stdio.h>
#include <string.h>

extern ADC_HandleTypeDef hadc;

extern TIM_HandleTypeDef htim1;
extern TIM_HandleTypeDef htim3;
extern TIM_HandleTypeDef htim15;
extern DMA_HandleTypeDef hdma_adc;
extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;

extern char uart_output[256];
extern uint16_t adc_dma_buf[1024];
extern __IO uint32_t g_RunDown;
extern __IO uint32_t totalNPL;

ADC_Ctrl g_adc_ctrl;
ADC_Status g_adc_status;
ADC_Result g_adc_Result;

void ADC_UpdateFastF() {
	totalNPL = g_adc_ctrl.nplcTimeCT * TIMCLKDIV;
	g_adc_ctrl.fastF = -g_adc_ctrl.refCT/totalNPL;
}


/**
初始化ADC控制参数, 控制参数在adc_config.h预设, 之后可通过命令行设置
*/
void ADC_CtrlInit(void) {
	g_adc_ctrl.nplc = NPLC;
	g_adc_ctrl.nplcTimeCT = NPLCCT;
	g_adc_ctrl.nplcTimeCT_Cur = NPLCCT;
	g_adc_ctrl.shortPluse = TZS;
	g_adc_ctrl.shortPluse_Cur = TZS;
	g_adc_ctrl.channel = 1;
	g_adc_ctrl.channel_Cur = 1;
	g_adc_ctrl.adcHigh = ADH;
	g_adc_ctrl.adcHigh_Cur = ADH;
	g_adc_ctrl.adcLow = ADL;
	g_adc_ctrl.adcLow_Cur = ADL;
	g_adc_ctrl.zeroN = 0;
	g_adc_ctrl.zeroP = 0;
	g_adc_ctrl.refRatio = 1.0064;
	g_adc_ctrl.az = 0;
	g_adc_ctrl.displayType = 0;
	g_adc_ctrl.refCT = 12680000;
	g_adc_ctrl.update = 0;
	g_adc_ctrl.type = 0;
	g_adc_Result.refn = 0;
	g_adc_Result.refp = 0;
	g_adc_Result.startFlag[0] = 's';
	g_adc_Result.startFlag[1] = 'f';
	g_adc_Result.endFlag[0] = 'e';
	g_adc_Result.endFlag[1] = 'f';
	g_adc_status.differ = 0;
	g_adc_status.isZero = 0;
	g_adc_status.preResult = 0;
	g_adc_status.preValue = 0;
	g_adc_status.totalN = 0;
	g_adc_status.totalP = 0;
	g_adc_status.sumST = 0;
	g_adc_status.countST = 0;
	g_adc_status.valueSt = 0;
	ADC_UpdateFastF();
}

void ADC_UpdateChannel(uint32_t ch) {
		if(ch) {
			HAL_GPIO_WritePin(MUXA0_GPIO_Port, MUXA0_Pin, GPIO_PIN_RESET);
		}
		else {
			HAL_GPIO_WritePin(MUXA0_GPIO_Port, MUXA0_Pin, GPIO_PIN_SET);
		}
		//delay_us(1000);
}

void ADC_UpdataStatus(void) {
	if(g_adc_ctrl.shortPluse != g_adc_ctrl.shortPluse_Cur) {
		g_adc_ctrl.shortPluse_Cur = g_adc_ctrl.shortPluse;
	}
	else if(g_adc_ctrl.adcHigh != g_adc_ctrl.adcHigh_Cur) {
		g_adc_ctrl.adcHigh_Cur = g_adc_ctrl.adcHigh;
	}
	else if(g_adc_ctrl.adcLow != g_adc_ctrl.adcLow_Cur) {
		g_adc_ctrl.adcLow_Cur = g_adc_ctrl.adcLow;
	}
	else if(g_adc_ctrl.channel != g_adc_ctrl.channel_Cur) {
		g_adc_ctrl.channel_Cur = g_adc_ctrl.channel;
		if(g_adc_ctrl.channel) {
			HAL_GPIO_WritePin(MUXA0_GPIO_Port, MUXA0_Pin, GPIO_PIN_RESET);
		}
		else {
			HAL_GPIO_WritePin(MUXA0_GPIO_Port, MUXA0_Pin, GPIO_PIN_SET);
		}
		//delay_us(1000);
	}
	else if(g_adc_ctrl.nplcTimeCT != g_adc_ctrl.nplcTimeCT_Cur) {
		g_adc_ctrl.nplcTimeCT_Cur = g_adc_ctrl.nplcTimeCT;
		htim3.Instance->ARR = g_adc_ctrl.nplcTimeCT + RUNDOWN - 1;
		htim3.Instance->CCR2 = g_adc_ctrl.nplcTimeCT;
		htim3.Instance->CNT = htim3.Instance->ARR-2;
		g_adc_ctrl.update = 1;
	}
	else if(g_adc_ctrl.az_Cur != g_adc_ctrl.az) {
		if(g_adc_ctrl.az_Cur) {
			ADC_UpdateChannel(g_adc_ctrl.channel_Cur);
		}
		g_adc_ctrl.az_Cur = g_adc_ctrl.az;
	}
	if(g_adc_ctrl.update) {
		g_adc_ctrl.update = 0;
		ADC_UpdateFastF();
	}
}

void ADC_StartDMACollect(void) {
	//开启tim15驱动ADC DMA, 存入adc_dma_buf, 监控积分波形, 找出慢速电压与时间关系
	hadc.Instance->CFGR1 &= ~(0x7 << 6);
	hadc.Instance->CFGR1 |= (0x4 << 6);
	__HAL_ADC_CLEAR_FLAG(&hadc, (ADC_FLAG_EOC | ADC_FLAG_EOS | ADC_FLAG_OVR));
	//设置DMA通道1
	/* Disable the DMA */
	hdma_adc.Instance->CCR &= ~DMA_CCR_EN;
	/* Clear all flags */
	hdma_adc.DmaBaseAddress->IFCR = (DMA_FLAG_GL1 << hdma_adc.ChannelIndex);
	/* Configure DMA Channel data length */
	hdma_adc.Instance->CNDTR = 1024;
	/* Configure DMA Channel source address */
	hdma_adc.Instance->CPAR = (uint32_t)&hadc.Instance->DR;
	/* Configure DMA Channel destination address */
	hdma_adc.Instance->CMAR = (uint32_t)adc_dma_buf;
	/* Enable the Peripheral */
	hdma_adc.Instance->CCR |= DMA_CCR_EN;
	// enable dma mode
	hadc.Instance->CFGR1 |= ADC_CFGR1_DMAEN;
	// disable adc it
	__HAL_ADC_DISABLE_IT(&hadc, ADC_IT_EOC);
	// enable timer
	htim15.Instance->CR1 |= (TIM_CR1_CEN);
}

void ADC_StopDMACollect(void) {
	htim15.Instance->CR1 &= ~(TIM_CR1_CEN);
	hdma_adc.Instance->CCR &= ~DMA_CCR_EN;
	hadc.Instance->CFGR1 &= ~ADC_CFGR1_DMAEN;
	hadc.Instance->CFGR1 &= ~(0x7 << 6);
	hadc.Instance->CFGR1 |= (0x1 << 6);
}

static void enableTim1OCInput(void) {
	TIM_IC_InitTypeDef sConfigIC = {0};
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = VZERO_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF2_TIM1;
  HAL_GPIO_Init(VZERO_GPIO_Port, &GPIO_InitStruct);
	sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 1;
  if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
	TIM_CCxChannelCmd(htim1.Instance, TIM_CHANNEL_3, TIM_CCx_ENABLE);
}

static void disableTim2OCInput(void) {
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = VZERO_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(VZERO_GPIO_Port, &GPIO_InitStruct);
	TIM_CCxChannelCmd(htim1.Instance, TIM_CHANNEL_3, TIM_CCx_ENABLE);
}

void ADC_Core(void)
{
  static double preValue;
  static float preV = 0;
  uint32_t rundownp1 = 0;
  uint32_t rundownp2 = 0;
  __IO uint32_t runupn1 = 0;
  __IO uint32_t tmp = 0;
  __IO uint32_t tmp2 = 0;
  htim1.Instance->CNT = 0;
  // 50>> force active 40>>forec inactive, 10 active on match,20>>inactive on match
  htim1.Instance->CCMR1 = 0x1040;
  htim1.Instance->CCR2 = 300;
	//等待正基准开启
  while ((htim1.Instance->CNT < htim1.Instance->CCR2) && (htim1.Instance->CNT < 50000))
  //等待积分电压<0
  while ((VZERO_GPIO_Port->IDR & VZERO_Pin) && (htim1.Instance->CNT < 50000))
    ;
  // 50 cnt后refp关闭,同时打开refn,积分电压上升
  if (htim1.Instance->CNT < 50000)
  {
    htim1.Instance->CCR2 = htim1.Instance->CNT + 50;
    htim1.Instance->CCR1 = htim1.Instance->CCR2;
    htim1.Instance->CCMR1 = 0x2010;
    rundownp1 = htim1.Instance->CCR2;
  }
  else
  {
    goto Error;
  }
  //等待积分电压>0
  // while(htim1.Instance->CCR2>htim1.Instance->CNT);
  while (!(VZERO_GPIO_Port->IDR & VZERO_Pin) && (htim1.Instance->CNT < 50000))
    ;
  if (htim1.Instance->CNT < 50000)
  {
    htim1.Instance->CCR1 = htim1.Instance->CNT + 50;
    htim1.Instance->CCMR1 = 0x4020;
		if(g_adc_ctrl.type == 1) {
			HAL_GPIO_WritePin(A0_GPIO_Port, A0_Pin, GPIO_PIN_SET);
		}
    // runup时间
    runupn1 = htim1.Instance->CCR1 - rundownp1;
    // CCR2-300是第一次rundown时间
    rundownp1 = rundownp1 - 300;
  }
  else
  {
    goto Error;
  }
  //等待积分电压>0
  while ((!(VZERO_GPIO_Port->IDR & VZERO_Pin)) && (htim1.Instance->CNT < 50000))
    ;
  if (htim1.Instance->CNT < 50000)
  {
    //正负基准同时开启,因为副基准绝对值较小, 积分电压将缓慢下降
    htim1.Instance->CCR2 = htim1.Instance->CNT + 500;
    htim1.Instance->CCR1 = htim1.Instance->CCR2;
    htim1.Instance->CCMR1 = 0x1010;
    tmp = htim1.Instance->CCR1 + 250;
		if(g_adc_ctrl.type == 1) {
			//开始dma采集放大后积分电压数值
			ADC_StartDMACollect();
		}
		else {
			enableTim1OCInput();
		}
    tmp = htim1.Instance->CCR2;
  }
  else
  {
    goto Error;
  }
  //等待正负基准开启
  while ((htim1.Instance->CNT < tmp) && (htim1.Instance->CNT < 50000))
    ;
	if(g_adc_ctrl.type == 1) {
		//等待积分(电压x20)<1000
		while ((hadc.Instance->DR > 1000) && (htim1.Instance->CNT < 50000))
			;
	}
	else {
		//等待积分电压<0
		while ((VZERO_GPIO_Port->IDR & VZERO_Pin) && (htim1.Instance->CNT < 50000))
    ;
	}
	//关闭正负基准,积分电压保持不变
	htim1.Instance->CCR2 = htim1.Instance->CNT + 350;
	htim1.Instance->CCR1 = htim1.Instance->CCR2;
	htim1.Instance->CCMR1 = 0x2020;
  //LOG1_GPIO_Port->BSRR = (uint32_t)LOG1_Pin;
  //LOG1_GPIO_Port->BRR = (uint32_t)LOG1_Pin;
  if (htim1.Instance->CNT < 50000)
  {
    // tmp2中存入dma传输个数
    tmp2 = hdma_adc.Instance->CNDTR;
    tmp2 = 1024 - tmp2;
    //第二次rundown时间,慢速
		if(g_adc_ctrl.type == 1) {
			rundownp2 = htim1.Instance->CCR2 - tmp;
			tmp = htim1.Instance->CCR1 + 3000;
		}
		else {
			rundownp2 = htim1.Instance->CCR3 - tmp;
			disableTim2OCInput();
		}
  }
  else
  {
    goto Error;
  }
	if(g_adc_ctrl.type == 1) {
		while ((htim1.Instance->CNT < tmp) && (htim1.Instance->CNT < 50000));
	}
  if (g_RunDown)
  {
		g_RunDown = 0;
		if(g_adc_ctrl.type == 1) {
			ADC_StopDMACollect();
			__HAL_ADC_ENABLE_IT(&hadc, ADC_IT_EOC);
			HAL_GPIO_WritePin(A0_GPIO_Port, A0_Pin, GPIO_PIN_RESET);
			//临时关闭tm3,进行输出
			htim3.Instance->CR1 &= ~(TIM_CR1_CEN);
			htim1.Instance->CR1 &= ~(TIM_CR1_CEN);
			htim1.Instance->CNT = 1000;
			tmp = hdma_adc.Instance->CNDTR;
			tmp = 1024 - tmp;
			int16_t prev = 0;
			int32_t sum2 = 0;
			int32_t count2 = 0;
			
			for (int i = 0; i < tmp; i++)
			{
				//printf("%d ",adc_dma_buf[i]);
				if (adc_dma_buf[i] < 3500)
				{
					if (i == tmp2)
					{
						g_adc_Result.step = g_adc_status.sumST;
						g_adc_Result.step = g_adc_Result.step / g_adc_status.countST;
						if(g_adc_status.countST > 1000) {
							g_adc_status.valueSt = g_adc_Result.step;
							g_adc_status.countST = 0;
							g_adc_status.sumST = 0;
						}
						//printf("\n");
					}
					if (i < tmp2 && prev > 0)
					{
						g_adc_status.sumST += prev - adc_dma_buf[i];
						g_adc_status.countST++;
						//printf("%d ",adc_dma_buf[i]);
					}
					else if(i>(tmp2+1) && (i != tmp - 1))
					{
							sum2 += adc_dma_buf[i];
							//printf("%d ",adc_dma_buf[i]);
							count2++;
					}
				}
				prev = adc_dma_buf[i];
			}
			//uint32_t tm3 = htim1.Instance->CNT - 1000;
			//printf("\n");
			g_adc_Result.remain = sum2;
			g_adc_Result.remain = g_adc_Result.remain/count2;
			g_adc_Result.cha = g_adc_Result.remain - preV;
			g_adc_Result.cha = (g_adc_Result.cha / g_adc_Result.step) * ADCFREQ;
			preV = g_adc_Result.remain;
		}
		else {
			uint16_t t = htim3.Instance->CCMR1;
			LOG1_GPIO_Port->BSRR = (uint32_t)LOG1_Pin;
			t = t & 0xFF00;
			htim3.Instance->CCMR1 = t | 0x50;
			htim3.Instance->CNT = htim3.Instance->ARR - 20;
			delay_us(100);
			htim3.Instance->CCR1 = htim3.Instance->ARR - 1;
			htim3.Instance->CCMR1 = t | 0x20;
			g_adc_Result.cha = 0;
			LOG1_GPIO_Port->BRR = (uint32_t)LOG1_Pin;
		}
		g_adc_Result.status = 1;
		double trefp, trefn, zrefp,zrefn;
    trefp = g_adc_Result.refp + rundownp1 + rundownp2 + g_adc_Result.cha;
    trefn = g_adc_Result.refn + runupn1 + rundownp2 + g_adc_Result.cha;
		uint8_t exportData = 1;
		if(g_adc_ctrl.az){
			if(g_adc_status.isZero) {
				g_adc_status.isZero = 0;
				exportData = 0;
				g_adc_status.totalN = trefn;
				g_adc_status.totalP = trefp;
				ADC_UpdateChannel(g_adc_ctrl.channel);
			}
			else {
				g_adc_status.isZero = 1;
				zrefn = trefn-g_adc_status.totalN;
				zrefp = trefp-g_adc_status.totalP;
				ADC_UpdateChannel(0);
			}
		}
		else {
			zrefp = trefp-g_adc_ctrl.zeroP;
			zrefn = trefn-g_adc_ctrl.zeroN;
		}
		uint32_t length = 0;
		if(exportData) {
			g_adc_Result.runDown1 = rundownp1;
			g_adc_Result.runUp2 = runupn1;
			g_adc_Result.runDown2 = rundownp2;
			g_adc_Result.totalN = zrefn;
			g_adc_Result.totalP = zrefp;
			//printf("%.9f\n",g_adc_ctrl.refRatio);
			double refct = zrefp*g_adc_ctrl.refRatio - zrefn;
			g_adc_Result.calcN = refct;
			g_adc_Result.result = refct * g_adc_ctrl.fastF;
			//uint32_t tm2 = htim1.Instance->CNT - 1000;
			if(g_adc_ctrl.displayType) {
				sprintf(uart_output,"s=1 st=%.1f re=%.1f rp=%d rn=%d rd1=%d rp1=%d rd2=%d sp=%.1f sn=%.1f zp=%.1f v=%.1f %.2f %.2f\n",
					g_adc_Result.step,g_adc_Result.remain,g_adc_Result.refp,g_adc_Result.refn,rundownp1, runupn1, rundownp2,trefp, trefn,refct, g_adc_Result.result, g_adc_Result.result - preValue, g_adc_Result.cha);
				length = strlen(uart_output);
			}
			else {
				//memcpy(uart_output, &g_adc_Result, sizeof(g_adc_Result));
				length = sizeof(g_adc_Result);
				uint8_t *p = (uint8_t *)&g_adc_Result;
				for(int i=0;i<length;i++) {
					HAL_UART_Transmit(&huart1, p+i, 1, 0xFFFF);
				}
			}
			//uint32_t tm = htim1.Instance->CNT - 1000;
			//printf("%d %d %d %d\n",tm, tm2, tm3, sizeof(ADC_Result));
			preValue = g_adc_Result.result;
			ADC_UpdataStatus();
		}
		if(g_adc_ctrl.type == 1) {
			htim3.Instance->CR1 |= (TIM_CR1_CEN);
			htim1.Instance->CR1 |= (TIM_CR1_CEN);
		}
		if(exportData) {
			UartSend(length);
		}
    return;
  }

Error:
  g_RunDown = 0;
  ADC_StopDMACollect();
  __HAL_ADC_ENABLE_IT(&hadc, ADC_IT_EOC);
  HAL_GPIO_WritePin(A0_GPIO_Port, A0_Pin, GPIO_PIN_RESET);
  g_adc_Result.status = 0;
	if(g_adc_ctrl.displayType) {
		printf("error...\n");
	}
	else {
		UartSend(sizeof(g_adc_Result));
	}
}
